/*
 Copyright (c) 2013 MeherTJ G. All rights reserved.
 License: LGPL for personnal study or free software.
 */

#pragma once

#include <memory>
#include <vector>
#include "zen_number.h"

namespace Zen {

	/**
	 channel: 1 mono, 2 double
	 sample size: bytes per sample block.
	 frequency: samples count per second.
	 sample count: total sample count.
	 */
	class Audio {
	public:
		static std::shared_ptr<Audio> Generate(size_t channel, size_t sample_size, size_t frequency, size_t sample_count);

		// tune: hz
		static std::shared_ptr<Audio> CreateSineWave(size_t channel, size_t sample_size, size_t frequency, size_t sample_count, float tune);

		size_t channel() const {
			return m_channel;
		}
		size_t sampleSize() const {
			return m_sample_size;
		}
		size_t sampleCount() const {
			return m_sample_count;
		}
		size_t frequency() const {
			return m_frequency;
		}
		size_t size() const {
			return m_buffer.size();
		}
		uint8_t* data() {
			return m_buffer.data();
		}
		uint8_t const* data() const {
			return m_buffer.data();
		}

	protected:
		Audio() = default;
		Audio(Audio&) = default;

		std::vector<uint8_t> m_buffer;
		uint16_t m_channel = 1;
		uint16_t m_sample_size = 1;
		uint32_t m_frequency = 0;
		uint32_t m_sample_count = 0;
	};

	class AudioDecoder
	{
	public:
		virtual std::shared_ptr<Audio> decode(std::vector<uint8_t> const& value) = 0;
		virtual ~AudioDecoder() = default;
	};

	class AudioEncoder
	{
	public:
		virtual std::vector<uint8_t> encode(Audio const&) = 0;
		virtual ~AudioEncoder() = default;
	};
}

namespace Zen {

	inline std::shared_ptr<Audio> Audio::Generate(size_t channel, size_t sample_size, size_t frequency, size_t sample_count)
	{
		auto audio = std::shared_ptr<Audio>(new Audio);
		audio->m_sample_size = (uint16_t)sample_size;
		audio->m_channel = (uint16_t)channel;
		audio->m_frequency = (uint32_t)frequency;
		audio->m_sample_count = (uint32_t)sample_count;

		audio->m_buffer.resize(0);
		audio->m_buffer.resize(sample_count * sample_size, 0);
		return audio;
	}

	inline std::shared_ptr<Audio> CreateSineWave(size_t channel, size_t sample_size, size_t frequency, float tuneHz, float sec)
	{
		if (sample_size == 1 && channel == 1)
		{
			auto step = float(frequency / tuneHz);
			int sample_count = (int)(frequency * sec);
			auto audio = Audio::Generate(channel, sample_size, frequency, sample_count);
			for (int64_t i = 0; i < sample_count; ++i)
			{
				auto v = 127 * cos(ZEN_F_2PI * (float)i / step);
				audio->data()[i] = (int8_t)v;
			}
			return audio;
		}
		return nullptr;
	}
}

